/*
========================================================================
 Name        : PublicTransportMapContainer.cpp
 Author      : 
 Copyright   : Your copyright notice
 Description : 
========================================================================
*/
// [[[ begin generated region: do not modify [Generated System Includes]
#include <aknviewappui.h>
#include <eikappui.h>
#include <SingaporeBus.rsg>
// ]]] end generated region [Generated System Includes]

// [[[ begin generated region: do not modify [Generated User Includes]
#include "PublicTransportMapContainer.h"
#include "PublicTransportMapContainerView.h"
#include "SingaporeBus.hrh"
#include "PublicTransportMapContainer.hrh"
#include "CSingaporeBusGenericView.hrh"
#include "SingaporeBusSettingItemList.hrh"
#include "SingaporeBusAccessPointsPriorityListBox.hrh"
#include "CSingaporeBusStopsView.hrh"
#include "CSingaporeBusServicesArrivalTimeView.hrh"
#include "CSingaporeBusRouteView.hrh"
#include "CSingaporeBusServiceRouteView.hrh"
#include "CSingaporeBusServicesView.hrh"
#include "CSingaporeBusFavoritesView.hrh"
// ]]] end generated region [Generated User Includes]
#include <aknglobalnote.h> 
#include "SingaporeBusAppUi.h"

#include <aknnotewrappers.h> 
#include <BAUTILS.H>
#include "SingaporeBusDocument.h"
#include "CharUtils.h"
#include <hal.h>

#include <euserhl.h>
#include <SingaporeBus.mbg>
#include <SingaporeBus_aif.mbg>

#include <Binder.h>
#include "MapUtils.h"

const TInt kZoomLevelDisplayStations = 5;

// [[[ begin generated region: do not modify [Generated Constants]
// ]]] end generated region [Generated Constants]


static void PrintNoteL(TRefByValue<const TDesC> aFormat, ...)
    {
    VA_LIST list;
    VA_START(list, aFormat);
    TBuf<256> buf;
    buf.FormatList(aFormat, list);
    VA_END(list);
	CAknGlobalNote* globalNote = CAknGlobalNote::NewLC();
	globalNote->ShowNoteL(EAknGlobalInformationNote, buf); 
    CleanupStack::PopAndDestroy(globalNote);
    }

/**
 * First phase of Symbian two-phase construction. Should not 
 * contain any code that could leave.
 */
CPublicTransportMapContainer::CPublicTransportMapContainer()
	{
	// [[[ begin generated region: do not modify [Generated Contents]
	// ]]] end generated region [Generated Contents]

	}
/** 
 * Destroy child controls.
 */
CPublicTransportMapContainer::~CPublicTransportMapContainer()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	// [[[ begin generated region: do not modify [Generated Contents]
	// ]]] end generated region [Generated Contents]
	
	iVisibleStations.Close();
	CGraphicsDevice* screenDevice=iCoeEnv->ScreenDevice();

	//screenDevice->ReleaseFont(iMapFont);	
	}
				
/**
 * Construct the control (first phase).
 *  Creates an instance and initializes it.
 *  Instance is not left on cleanup stack.
 * @param aRect bounding rectangle
 * @param aParent owning parent, or NULL
 * @param aCommandObserver command observer
 * @return initialized instance of CPublicTransportMapContainer
 */
CPublicTransportMapContainer* CPublicTransportMapContainer::NewL( 
		const TRect& aRect, 
		const CCoeControl* aParent, 
		MEikCommandObserver* aCommandObserver )
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	CPublicTransportMapContainer* self = CPublicTransportMapContainer::NewLC( 
			aRect, 
			aParent, 
			aCommandObserver );
	CleanupStack::Pop( self );
	return self;
	}

/**
 * Construct the control (first phase).
 *  Creates an instance and initializes it.
 *  Instance is left on cleanup stack.
 * @param aRect The rectangle for this window
 * @param aParent owning parent, or NULL
 * @param aCommandObserver command observer
 * @return new instance of CPublicTransportMapContainer
 */
CPublicTransportMapContainer* CPublicTransportMapContainer::NewLC( 
		const TRect& aRect, 
		const CCoeControl* aParent, 
		MEikCommandObserver* aCommandObserver )
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	CPublicTransportMapContainer* self = new ( ELeave ) CPublicTransportMapContainer();
	CleanupStack::PushL( self );
	self->ConstructL( aRect, aParent, aCommandObserver );
	return self;
	}

/**
 * Construct the control (second phase).
 *  Creates a window to contain the controls and activates it.
 * @param aRect bounding rectangle
 * @param aCommandObserver command observer
 * @param aParent owning parent, or NULL
 */ 
void CPublicTransportMapContainer::ConstructL( 
		const TRect& aRect, 
		const CCoeControl* aParent, 
		MEikCommandObserver* aCommandObserver )
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);

	if ( aParent == NULL )
	    {
		CreateWindowL();
	    }
	else
	    {
	    SetContainerWindowL( *aParent );
	    }
	
	
	
	
	iFocusControl = NULL;
	iCommandObserver = aCommandObserver;
	InitializeControlsL();
	
	
	_LIT( kSingaporeBus_aifFile, "\\resource\\apps\\SingaporeBus_aif.mif" );
	_LIT( kSingaporeBus_mbmFile, "\\resource\\apps\\SingaporeBus.mbm" );
	//TSize busStationIconSize ( Min(aRect.Width(), aRect.Height())/12, Min(aRect.Width(), aRect.Height())/12 );
	TSize busStationIconSize ( 24, 24 );
	iBusStationIcon = LoadAndScaleIconL(
			kSingaporeBus_aifFile, EMbmSingaporebus_aifSingaporebusstationmap, EMbmSingaporebus_aifSingaporebusstationmap_mask,
			&busStationIconSize, EAspectRatioPreserved );
	iMrtStationIcon = LoadAndScaleIconL(
			kSingaporeBus_mbmFile, EMbmSingaporebusIcon_mrt, -1,
			NULL, EAspectRatioPreserved );
	iStarIcon = LoadAndScaleIconL(
			kSingaporeBus_aifFile, EMbmSingaporebus_aifStar, EMbmSingaporebus_aifStar_mask,
			&busStationIconSize, EAspectRatioPreserved );
	iFlagOrigIcon = LoadAndScaleIconL(
			kSingaporeBus_aifFile, EMbmSingaporebus_aifFlag_orig, EMbmSingaporebus_aifFlag_orig_mask,
			&busStationIconSize, EAspectRatioPreserved );
	iFlagDestIcon = LoadAndScaleIconL(
			kSingaporeBus_aifFile, EMbmSingaporebus_aifFlag_dest, EMbmSingaporebus_aifFlag_dest_mask,
			&busStationIconSize, EAspectRatioPreserved );
	

	iTilesSize = TSize(256, 256);
	
	{
		iLastEButton1Down = 0;
		iDragging = EFalse;
	}
	
	{
		iMapFont = CEikonEnv::Static()->LegendFont();
	}
	
	
	{
	iServiceNameRect.SetRect(-1, -1, -1, -1);
	iZoomInRect.SetRect(-1, -1, -1, -1);
	iZoomOutRect.SetRect(-1, -1, -1, -1);
	iCenterMapOnPositionRect.SetRect(-1, -1, -1, -1);
	iRefreshPositionRect.SetRect(-1, -1, -1, -1);
	}
	
	SetRect( aRect );
	ActivateL();
	EnableDragEvents();			
	// [[[ begin generated region: do not modify [Post-ActivateL initializations]
	// ]]] end generated region [Post-ActivateL initializations]
	
	CSingaporeBusDocument* doc = (CSingaporeBusDocument*)CEikonEnv::Static()->EikAppUi()->Document();
	CPublicTransportMapContainerView* view = (CPublicTransportMapContainerView*)iAvkonViewAppUi->View( TUid::Uid( EPublicTransportMapContainerViewId ) );
	if(view->iSelectedStation)
		CenterMapOn(view->iSelectedStation->iCoord);
	else
		{
		if(view->iZoomLevel >= kZoomLevelDisplayStations) RefreshVisibleStationsL();
		}
	
	TInt initialDisplayServiceKey = view->iCurrentDisplayServiceKey;
	if(!LoadCurrentDisplayServiceL() || initialDisplayServiceKey != view->iCurrentDisplayServiceKey)
	{
		const TDesC8& serviceKey = *view->iDisplayServiceKeys[initialDisplayServiceKey];
		TPtrC8 serviceName = serviceKey.Left( serviceKey.Locate(' ') );
		TBuf<256> buf;
		buf.Format(_L("Unknown path for %S"), narrowToWideLC(serviceName));
		CleanupStack::PopAndDestroy();
		CAknWarningNote* note = new (ELeave) CAknWarningNote(ETrue);
		note->ExecuteLD(buf);
	}

	iFreeScrollPeriodic = CPeriodic::NewL(CActive::EPriorityHigh);
	//CImageDecoderEx::StartThread();
	
	DrawToBackBuffer();
	
#if !defined(__SERIES60_3X__) || defined(__S60_50__)
	    this->iLongTapDetector = CAknLongTapDetector::NewL(this);
		//http://www.developer.nokia.com/Community/Wiki/Title_Pane_Touch_Observer_API
	    CEikStatusPane* statusPane = STATIC_CAST( CAknAppUi*, CEikonEnv::Static()->EikAppUi() )->StatusPane();
	    if (statusPane)
	    {
	       // Title pane UID
	       TUid titlePaneUid; 
	       titlePaneUid.iUid = EEikStatusPaneUidTitle;
	       // Get pointer to CAknTitlePane object 
	       CAknTitlePane* titlePane = (CAknTitlePane*) statusPane->ControlL(titlePaneUid);
	       // Set this AppUi object as the observer of the title pane
	       titlePane->SetTitlePaneObserver(this);
	    }
#endif
	    iPositionTracking = ETrue;
	    
	}


CGulIcon* CPublicTransportMapContainer::LoadAndScaleIconL( 
		const TDesC& aFileName,
		TInt aBitmapId, 
		TInt aMaskId, 
		TSize* aSize, 
		TScaleMode aScaleMode )
	{
	CFbsBitmap* bitmap;
	CFbsBitmap* mask;
	AknIconUtils::CreateIconL( bitmap, mask, aFileName, aBitmapId, aMaskId );
	
	TSize size;
	if ( aSize == NULL )
		{
		// Use size from the image header.  In case of SVG,
		// we preserve the image data for a while longer, since ordinarily
		// it is disposed at the first GetContentDimensions() or SetSize() call.
		AknIconUtils::PreserveIconData( bitmap );
		AknIconUtils::GetContentDimensions( bitmap, size );
		}
	else
		{
		size = *aSize;
		}
	
	AknIconUtils::SetSize( bitmap, size, aScaleMode );
	AknIconUtils::SetSize( mask, size, aScaleMode );
	
	if ( aSize == NULL )
		{
		AknIconUtils::DestroyIconData( bitmap );
		}
	
	return CGulIcon::NewL( bitmap, mask );
	}

TBool CPublicTransportMapContainer::LoadCurrentDisplayServiceL()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
CPublicTransportMapContainerView* view = (CPublicTransportMapContainerView*)iAvkonViewAppUi->View( TUid::Uid( EPublicTransportMapContainerViewId ) );
CSingaporeBusDocument* doc = (CSingaporeBusDocument*)CEikonEnv::Static()->EikAppUi()->Document();
	if(view->iDisplayServiceKeys.Count())
		{
		TInt orig = view->iCurrentDisplayServiceKey;
		while(!doc->LoadServicePathL(*view->iDisplayServiceKeys[view->iCurrentDisplayServiceKey]))
			{
				view->iCurrentDisplayServiceKey = (view->iCurrentDisplayServiceKey + 1) % view->iDisplayServiceKeys.Count();
				if(view->iCurrentDisplayServiceKey == orig) return EFalse;
			}
		}
	return ETrue;
	}


/**
* Return the number of controls in the container (override)
* @return count
*/
TInt CPublicTransportMapContainer::CountComponentControls() const
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);

return ( int ) ELastControl;

	}
				
/**
* Get the control with the given index (override)
* @param aIndex Control index [0...n) (limited by #CountComponentControls)
* @return Pointer to control
*/
CCoeControl* CPublicTransportMapContainer::ComponentControl( TInt aIndex ) const
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	// [[[ begin generated region: do not modify [Generated Contents]
	switch ( aIndex )
		{
		}
	// ]]] end generated region [Generated Contents]

	// handle any user controls here...
	
	return NULL;
	}
				
/**
 *	Handle resizing of the container. This implementation will lay out
 *  full-sized controls like list boxes for any screen size, and will layout
 *  labels, editors, etc. to the size they were given in the UI designer.
 *  This code will need to be modified to adjust arbitrary controls to
 *  any screen size.
 */				
void CPublicTransportMapContainer::SizeChanged()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	CCoeControl::SizeChanged();
	LayoutControls();
	// [[[ begin generated region: do not modify [Generated Contents]
			
	// ]]] end generated region [Generated Contents]
	
    iBackBuffer = new (ELeave) CWsBitmap; 
	User::LeaveIfError( iBackBuffer->Create(Size(), Window().DisplayMode()));
	// Create back buffer graphics context
	iBackBufferDevice = CFbsBitmapDevice::NewL(iBackBuffer.Get());
	CFbsBitGc* backBufferContext = NULL;
	User::LeaveIfError(iBackBufferDevice->CreateContext(backBufferContext));
	iBackBufferContext = backBufferContext;
	iBackBufferContext->SetPenStyle(CGraphicsContext::ESolidPen);
	iBackBufferSize = iBackBuffer->SizeInPixels();
	
	if(AknLayoutUtils::PenEnabled())
		{
		CWsScreenDevice* screenDevice = CEikonEnv::Static()->ScreenDevice();
		TPixelsAndRotation par;
		screenDevice->GetDefaultScreenSizeAndRotation(par);
		const TRect rect = Rect();
		const TInt size = Min( par.iPixelSize.iHeight, par.iPixelSize.iWidth ) / 7;
		iZoomInRect.SetRect(0, rect.Height() - size, size, rect.Height());
		iZoomOutRect.SetRect(rect.Width()- size, rect.Height() - size, rect.Width(),rect.Height());
		iCenterMapOnPositionRect.SetRect(rect.Width()- size, 0, rect.Width(), size);
		iRefreshPositionRect.SetRect(rect.Center().iX - size/2, rect.Height() - size, rect.Center().iX + size/2, rect.Height());
		
		_LIT( kSingaporeBus_aifFile, "\\resource\\apps\\SingaporeBus_aif.mif" );
		TSize iZoomInSize = iZoomInRect.Size();
		TSize iZoomOutSize = iZoomOutRect.Size();
		TSize iCenterMapOnPositionSize = iCenterMapOnPositionRect.Size();
		TSize iRefreshPositionSize = iRefreshPositionRect.Size();
		iZoomInIcon = LoadAndScaleIconL(kSingaporeBus_aifFile, EMbmSingaporebus_aifZoomin, EMbmSingaporebus_aifZoomin_mask, &iZoomInSize, EAspectRatioPreserved);
		iZoomOutIcon = LoadAndScaleIconL(kSingaporeBus_aifFile, EMbmSingaporebus_aifZoomout, EMbmSingaporebus_aifZoomout_mask, &iZoomOutSize, EAspectRatioPreserved);
		iCenterMapOnPositionIcon = LoadAndScaleIconL(kSingaporeBus_aifFile, EMbmSingaporebus_aifCentermaponposition, EMbmSingaporebus_aifCentermaponposition_mask, &iCenterMapOnPositionSize, EAspectRatioPreserved);
		iRefreshPositionIcon = LoadAndScaleIconL(kSingaporeBus_aifFile, EMbmSingaporebus_aifRefreshposition, EMbmSingaporebus_aifRefreshposition_mask, &iRefreshPositionSize, EAspectRatioPreserved);
		
		}
	DrawToBackBuffer();
	DrawDeferred();
	}
				
// [[[ begin generated function: do not modify
/**
 * Layout components as specified in the UI Designer
 */
void CPublicTransportMapContainer::LayoutControls()
	{
	}
// ]]] end generated function


static TReal64 TLinearOrder_Match_target;
static TInt TLinearOrder_Match(const TStation* const& left, const TStation* const& right)
	{
	TBool
		leftMatches = (left->iCoord.Longitude() >= TLinearOrder_Match_target),
		rightMatches = (right->iCoord.Longitude() >= TLinearOrder_Match_target);
	if(leftMatches == rightMatches) return 0;
	if(leftMatches && !rightMatches) return 1;
	return -1;
	}

void CPublicTransportMapContainer::RefreshVisibleStationsL()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	CSingaporeBusDocument* doc = (CSingaporeBusDocument*)CEikonEnv::Static()->EikAppUi()->Document();
	CPublicTransportMapContainerView* view = (CPublicTransportMapContainerView*)iAvkonViewAppUi->View( TUid::Uid( EPublicTransportMapContainerViewId ) );
	iVisibleStations.Reset();
	const TCoordinate minLatLong (
			view->iOrig.Latitude() - kTilesResolutions[view->iZoomLevel] * YScale(view->iOrig) * Rect().Height(),
			view->iOrig.Longitude());
	const TCoordinate maxLatLong (
			view->iOrig.Latitude(),
			view->iOrig.Longitude() + kTilesResolutions[view->iZoomLevel] * Rect().Width());
	TInt i;
	// skip the smaller longitudes
	{
		TStation target;
		target.iCoord = view->iOrig;
		TLinearOrder_Match_target = target.iCoord.Longitude();
		TInt ret = view->iStationsOrderedByLongitude.SpecificFindInOrder(&target, TLinearOrder<const TStation*>(&TLinearOrder_Match), EArrayFindMode_First);
		i = (ret == KErrNotFound) ?  view->iStationsOrderedByLongitude.Count() : ret;
	}
	
	for(  ; i < view->iStationsOrderedByLongitude.Count() && view->iStationsOrderedByLongitude[i]->iCoord.Longitude() <= maxLatLong.Longitude() ; ++i)
		{
		if(view->iStationsOrderedByLongitude[i]->iCoord.Latitude() >= minLatLong.Latitude() && view->iStationsOrderedByLongitude[i]->iCoord.Latitude() <= maxLatLong.Latitude())
			iVisibleStations.AppendL( view->iStationsOrderedByLongitude[i] );		
		}	
	}

const TStation* CPublicTransportMapContainer::FindNextVisibleStationL(const TStation* aFromStation, const TCoordinate& aDirection)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	const TStation* nextStation = NULL;
	TReal distanceNextStation = 0;
	for(TInt i = 0 ; i < iVisibleStations.Count() ; ++i)
		{
		if(iVisibleStations[i] == aFromStation) continue;

		const TStation* station = iVisibleStations[i];

		const TCoordinate vectorStation(
				station->iCoord.Latitude() - aFromStation->iCoord.Latitude(),
				station->iCoord.Longitude() - aFromStation->iCoord.Longitude());
		
/*		if(
				vectorStation.Latitude()*(aDirection.Latitude() - aDirection.Longitude()) + vectorStation.Longitude()*(aDirection.Longitude() + aDirection.Latitude()) > 0 &&
				vectorStation.Latitude()*(aDirection.Latitude() + aDirection.Longitude()) + vectorStation.Longitude()*(aDirection.Longitude() - aDirection.Latitude()) > 0
			)*/
		if(	vectorStation.Latitude()*aDirection.Latitude() + vectorStation.Longitude()*aDirection.Longitude() > 0 )
			{
			TReal distanceStation = vectorStation.Latitude()*vectorStation.Latitude() + vectorStation.Longitude()*vectorStation.Longitude();
			if(!nextStation || distanceStation < distanceNextStation)
				{
				distanceNextStation = distanceStation;
				nextStation = iVisibleStations[i];
				}
			}
		}
	return nextStation;
	}


const TStation* CPublicTransportMapContainer::FindClosestVisibleStationL(const TCoordinate& aPos)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	const TStation* nextStation = NULL;
	TReal distanceNextStation = 0;
	for(TInt i = 0 ; i < iVisibleStations.Count() ; ++i)
		{
		const TStation* station = iVisibleStations[i];

		const TCoordinate vectorStation(
				station->iCoord.Latitude() - aPos.Latitude(),
				station->iCoord.Longitude() - aPos.Longitude());
		
		TReal distanceStation = vectorStation.Latitude()*vectorStation.Latitude() + vectorStation.Longitude()*vectorStation.Longitude();
		if(!nextStation || distanceStation < distanceNextStation)
			{
			distanceNextStation = distanceStation;
			nextStation = iVisibleStations[i];
			}
		}
	return nextStation;
	}


static void MessageBox(const TDesC& aString)
	{
	CAknInformationNote* note = new (ELeave) CAknInformationNote(ETrue);
	note->ExecuteLD(aString);	
	User::After(100000);
	}

TInt CPublicTransportMapContainer::FreeScrollCallback()
	{
	
	
	
	TTime currentTime;
	currentTime.UniversalTime();
	TInt64 microSeconds = currentTime.MicroSecondsFrom(iFreeScrollCallbackTime).Int64();
	
	CPublicTransportMapContainerView* view = (CPublicTransportMapContainerView*)iAvkonViewAppUi->View( TUid::Uid( EPublicTransportMapContainerViewId ) );
	CSingaporeBusDocument* doc = (CSingaporeBusDocument*)CEikonEnv::Static()->EikAppUi()->Document();
	
	TPoint scrollVector (
			TInt64(iFreeScrollSpeed.iX)*microSeconds/(1000000*100),
			TInt64(iFreeScrollSpeed.iY)*microSeconds/(1000000*100)
			);
	view->iOrig.SetCoordinate(
			view->iOrig.Latitude() + kTilesResolutions[view->iZoomLevel]* YScale(view->iOrig) *scrollVector.iY,
			view->iOrig.Longitude() - kTilesResolutions[view->iZoomLevel]*scrollVector.iX);
	doc->iMapTileServer->DownloadVisibleTilesL(view->iOrig, view->iZoomLevel, Rect().Size());
	
	
	{
	TPoint delta = (*iFreeScrollFunction)(iFreeScrollSpeed, iOrigFreeScrollSpeed, microSeconds);
	iFreeScrollSpeed += delta;
	
	if(TInt64(iFreeScrollSpeed.iX) * TInt64(iOrigFreeScrollSpeed.iX) < 0 || TInt64(iFreeScrollSpeed.iX)*TInt64(iFreeScrollSpeed.iX) < 200*200) // sign change or speed too small
		iFreeScrollSpeed.iX = 0;
	if(TInt64(iFreeScrollSpeed.iY) * TInt64(iOrigFreeScrollSpeed.iY) < 0 || TInt64(iFreeScrollSpeed.iY)*TInt64(iFreeScrollSpeed.iY) < 200*200) // sign change or speed too small
		iFreeScrollSpeed.iY = 0;
	
	// simulate movement
	/*
	{
	if(iFreeScrollSpeed.iX == 0 && iFreeScrollSpeed.iY == 0)
		{
		iFreeScrollSpeed += TPoint(100*100*(Math::Random()%20 + 1), 100*100*(Math::Random()%20 + 1));
		if(view->iOrig.Latitude() > 1.4) iFreeScrollSpeed.iY = -Abs(iFreeScrollSpeed.iY);
		else if(view->iOrig.Latitude() < 1.3) iFreeScrollSpeed.iY = Abs(iFreeScrollSpeed.iY);
		if(view->iOrig.Longitude() > 103.9) iFreeScrollSpeed.iX = Abs(iFreeScrollSpeed.iX);
		else if(view->iOrig.Longitude() < 103.7) iFreeScrollSpeed.iX = -Abs(iFreeScrollSpeed.iX);
		}
	}*/
	
	
	iFreeScrollCallbackTime = currentTime;
	
	TInt delayNextFrame =
			 Min(
				(iFreeScrollSpeed.iX == 0) ? KMaxTInt : Abs(TInt64(100*1000000) / (TInt64(iFreeScrollSpeed.iX))),
				(iFreeScrollSpeed.iY == 0) ? KMaxTInt : Abs(TInt64(100*1000000) / (TInt64(iFreeScrollSpeed.iY)))
				);
	iFreeScrollPeriodic->Cancel();
	if(iFreeScrollSpeed.iX || iFreeScrollSpeed.iY)
		iFreeScrollPeriodic->Start(delayNextFrame, KMaxTInt, TCallBack(&MemFunDelegate<CPublicTransportMapContainer, &CPublicTransportMapContainer::FreeScrollCallback>, this));
	}
	
	
	
	if(view->iZoomLevel >= kZoomLevelDisplayStations)
		{
		const TStation* newSelectedStation = NULL;
		TUint32 isqrt(TUint32 x);
		TUint32 iFreeScrollSpeedLen = isqrt(iFreeScrollSpeed.iX*iFreeScrollSpeed.iX + iFreeScrollSpeed.iY*iFreeScrollSpeed.iY);
		
		TCoordinate direction (
				TReal64(iFreeScrollSpeed.iY)/TReal64(iFreeScrollSpeedLen),
				TReal64(-iFreeScrollSpeed.iX)/TReal64(iFreeScrollSpeedLen)
				);
		RefreshVisibleStationsL();
		/*
		if(view->iSelectedStation)
			newSelectedStation = ( FindNextVisibleStationL(view->iSelectedStation, direction) );
		if(newSelectedStation)
			view->iSelectedStation = ( newSelectedStation );
		else if(iVisibleStations.Count() == 0)
			view->iSelectedStation = NULL; // no selected station since no station is visible
		else if(!view->iSelectedStation)
			view->iSelectedStation = ( iVisibleStations[0] );*/
		}
	DrawToBackBuffer();
	//DrawDeferred();
	DrawNow();
	

	
	return (iFreeScrollSpeed.iX != 0 || iFreeScrollSpeed.iY != 0);
	}

TPoint NoDeceleration(const TPoint& aCurrentSpeed, const TPoint& aOrigSpeed, const TInt64& aMicroSeconds)
	{
	return TPoint(0,0);
	}
TPoint InverseExpDeceleration(const TPoint& aCurrentSpeed, const TPoint& aOrigSpeed, const TInt64& aMicroSeconds)
	{
	const TInt frictionNum = 15, frictionDenom = 10;
	return TPoint(
			(-TInt64(aCurrentSpeed.iX)*frictionNum*aMicroSeconds)/(1000000*frictionDenom),
			(-TInt64(aCurrentSpeed.iY)*frictionNum*aMicroSeconds)/(1000000*frictionDenom)
			);
	}
TPoint ExpDeceleration(const TPoint& aCurrentSpeed, const TPoint& aOrigSpeed, const TInt64& aMicroSeconds)
	{
	const TInt frictionNum = 15, frictionDenom = 10;
	return TPoint(
			(TInt64(aCurrentSpeed.iX - 2*aOrigSpeed.iX)*frictionNum*aMicroSeconds)/(1000000*frictionDenom),
			(TInt64(aCurrentSpeed.iY - 2*aOrigSpeed.iY)*frictionNum*aMicroSeconds)/(1000000*frictionDenom)
			);
	}


const TInt kSingleTapTime = 150 * 1000;

/**
 *	Handle pointer events.
 */				
void CPublicTransportMapContainer::HandlePointerEventL(const TPointerEvent& aPointerEvent)
    {
	TFunTrace funTrace(__PRETTY_FUNCTION__);
    // Remember to call base class implementation
    CCoeControl::HandlePointerEventL(aPointerEvent);
    
#if !defined(__SERIES60_3X__) || defined(__S60_50__)
    if(LongTapPointerEventL(aPointerEvent))
    	return;
#endif

	CSingaporeBusDocument* doc = (CSingaporeBusDocument*)CEikonEnv::Static()->EikAppUi()->Document();
	CPublicTransportMapContainerView* view = (CPublicTransportMapContainerView*)iAvkonViewAppUi->View( TUid::Uid( EPublicTransportMapContainerViewId ) );
    TTime currentTime;
    currentTime.UniversalTime();
    switch(aPointerEvent.iType)
    	{
		case TPointerEvent::EButton1Down:
			{
			iDragTimes[0].UniversalTime();
			iDragTimes[1] = iDragTimes[0];
			iDragPositions[0] = aPointerEvent.iPosition;
			iDragPositions[1] = iDragPositions[0];
			iFreeScrollPeriodic->Cancel();
					
			if(iServiceNameRect.Contains(aPointerEvent.iPosition))
				{
				iDragging = EFalse;
				if (view->iDisplayServiceKeys.Count())
					{
					view->iCurrentDisplayServiceKey = (view->iCurrentDisplayServiceKey + 1) % view->iDisplayServiceKeys.Count();
					LoadCurrentDisplayServiceL();
					}				
				}
			else if(iZoomInRect.Contains(aPointerEvent.iPosition))
				{
					iDragging = EFalse;
					ZoomTo( Min( view->iZoomLevel + 1, ZoomLevels() - 1 ) );
					view->UpdateTitle();
			    	DrawToBackBuffer();
					DrawDeferred();
				}
			else if(iZoomOutRect.Contains(aPointerEvent.iPosition))
				{
					iDragging = EFalse;
					ZoomTo( Max( view->iZoomLevel - 1, 0 ) );
					view->UpdateTitle();
			    	DrawToBackBuffer();
					DrawDeferred();
				}
			else if(iCenterMapOnPositionRect.Contains(aPointerEvent.iPosition))
				{
					iDragging = EFalse;
					if(doc->iPositioningStatus == CSingaporeBusDocument::PS_FOUND)
						CenterMapOn(doc->iPosition);
			    	DrawToBackBuffer();
			    	iPositionTracking = ETrue;
			    	DrawDeferred();
				}
			else if(iRefreshPositionRect.Contains(aPointerEvent.iPosition))
				{
				iDragging = EFalse;
				view->HandleCommandL(EPublicTransportMapContainerViewRefresh_positionMenuItemCommand);
				}
			else
				{
				iDragStart = aPointerEvent.iPosition;
				iLastEButton1Down = currentTime;
				// select nearby station
				{
				if(view->iZoomLevel >= kZoomLevelDisplayStations)
					{
					TCoordinate pos (
							view->iOrig.Latitude()-aPointerEvent.iPosition.iY*kTilesResolutions[view->iZoomLevel]*YScale(view->iOrig),
							view->iOrig.Longitude()+aPointerEvent.iPosition.iX*kTilesResolutions[view->iZoomLevel]
							);
					iSelectedStationBeforeLastEButton1Down = view->iSelectedStation;
					view->iSelectedStation = FindClosestVisibleStationL(pos);
					view->UpdateTitle();
			    	DrawToBackBuffer();
					DrawDeferred();
					}
				}
				iDragging = ETrue;
				}
			}
			break;
		case TPointerEvent::EButton1Up:
			{
			
			if(iDragStart == aPointerEvent.iPosition)
				{
				//single tap
				if(iSelectedStationBeforeLastEButton1Down)
					{
					const TStation* station = iSelectedStationBeforeLastEButton1Down;
					
					const TInt
						stationX = (station->iCoord.Longitude() - view->iOrig.Longitude()) / kTilesResolutions[view->iZoomLevel],
						stationY = (view->iOrig.Latitude() - station->iCoord.Latitude()) / (kTilesResolutions[view->iZoomLevel]*YScale(view->iOrig));
					if(iSelectedStationBeforeLastEButton1Down == view->iSelectedStation &&
						(iDragStart.iX - stationX)*(iDragStart.iX - stationX) + (iDragStart.iY - stationY)*(iDragStart.iY - stationY) < 20*20)
						{
						if(view->iSelectedStation && view->iSelectedStation->iStationNumber.Length() >= 4)
							{
							TBuf8<128> buf;
							StoreCustomMessageParamL(buf, _L8("id"), _L8("%S"), &view->iSelectedStation->iStationNumber);
							iAvkonViewAppUi->ActivateLocalViewL(TUid::Uid( ESingaporeBusServicesArrivalTimeViewId ), TUid::Uid(0), buf);
							}
						}
					}
				
				// freeScrolling
					{
					TTime currentTime;
					currentTime.UniversalTime();
					TInt microSeconds = currentTime.MicroSecondsFrom(iDragTimes[1]).Int64();
					if(microSeconds)
						{
						iFreeScrollSpeed.SetXY(
								-TInt64(iDragPositions[1].iX - aPointerEvent.iPosition.iX)*1000000*100/microSeconds,
								-TInt64(iDragPositions[1].iY - aPointerEvent.iPosition.iY)*1000000*100/microSeconds
								);
						iFreeScrollCallbackTime.UniversalTime();
						iOrigFreeScrollSpeed = iFreeScrollSpeed;
						iFreeScrollFunction = &InverseExpDeceleration;
						iFreeScrollPeriodic->Cancel();
						iFreeScrollPeriodic->Start( 0, KMaxTInt, TCallBack(&MemFunDelegate<CPublicTransportMapContainer, &CPublicTransportMapContainer::FreeScrollCallback>, this) );
						}
					}

				}
			}
			break;
		case TPointerEvent::EButton2Down:
			break;
		case TPointerEvent::EButton2Up:
			break;
		case TPointerEvent::EButton3Down:
			break;
		case TPointerEvent::EButton3Up:
			break;
		case TPointerEvent::EDrag:
			{
			iDragTimes[1] = iDragTimes[0];
			iDragTimes[0].UniversalTime();
			iDragPositions[1] = iDragPositions[0];
			iDragPositions[0] = aPointerEvent.iPosition;
			iPositionTracking = EFalse;
			
			if(iDragging)
				{
				CPublicTransportMapContainerView* view = (CPublicTransportMapContainerView*)iAvkonViewAppUi->View( TUid::Uid( EPublicTransportMapContainerViewId ) );
				TPoint dragVector = aPointerEvent.iPosition - iDragStart;
				view->iOrig.SetCoordinate(
						view->iOrig.Latitude() + kTilesResolutions[view->iZoomLevel]*YScale(view->iOrig)*dragVector.iY,
						view->iOrig.Longitude() - kTilesResolutions[view->iZoomLevel]*dragVector.iX);
				doc->iMapTileServer->DownloadVisibleTilesL(view->iOrig, view->iZoomLevel, Rect().Size());
				
				if(view->iZoomLevel >= kZoomLevelDisplayStations)
					RefreshVisibleStationsL();
		    	DrawToBackBuffer();
		    	DrawNow();
				iDragStart = aPointerEvent.iPosition;
				}
			}
			break;
		case TPointerEvent::EMove:
			break;
		case TPointerEvent::EButtonRepeat:
			break;
		case TPointerEvent::ESwitchOn:
			break;
    	}
    
    // Your additional code here
    // ...
    }

void CPublicTransportMapContainer::ZoomTo(TInt aZoomLevel)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	CPublicTransportMapContainerView* view = (CPublicTransportMapContainerView*)iAvkonViewAppUi->View( TUid::Uid( EPublicTransportMapContainerViewId ) );
	CSingaporeBusDocument* doc = (CSingaporeBusDocument*)CEikonEnv::Static()->EikAppUi()->Document();
	TCoordinate shift(
			Rect().Width()/2*( kTilesResolutions[aZoomLevel] - kTilesResolutions[view->iZoomLevel] )*YScale(view->iOrig),
			Rect().Height()/2*( kTilesResolutions[view->iZoomLevel] - kTilesResolutions[aZoomLevel] )
			);
	view->iOrig.SetCoordinate(
			view->iOrig.Latitude() + shift.Latitude(),
			view->iOrig.Longitude() + shift.Longitude() );
	view->iZoomLevel = aZoomLevel;	
	doc->iMapTileServer->DownloadVisibleTilesL(view->iOrig, view->iZoomLevel, Rect().Size());
	if(view->iZoomLevel >= kZoomLevelDisplayStations)
		{
		RefreshVisibleStationsL();
		if(view->iSelectedStation && iVisibleStations.Find(view->iSelectedStation) == KErrNotFound)
			view->iSelectedStation = FindNextVisibleStationL(view->iSelectedStation, shift);
		if(!view->iSelectedStation && iVisibleStations.Count() != 0)
			view->iSelectedStation = iVisibleStations[0];
		}
	else view->iSelectedStation = NULL;
	view->UpdateTitle();
	}


/**
 *	Handle key events.
 */				
TKeyResponse CPublicTransportMapContainer::OfferKeyEventL( 
		const TKeyEvent& aKeyEvent, 
		TEventCode aType )
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	// [[[ begin generated region: do not modify [Generated Contents]
	
	// ]]] end generated region [Generated Contents]

	
	CSingaporeBusDocument* doc = (CSingaporeBusDocument*)CEikonEnv::Static()->EikAppUi()->Document();
	CPublicTransportMapContainerView* view = (CPublicTransportMapContainerView*)iAvkonViewAppUi->View( TUid::Uid( EPublicTransportMapContainerViewId ) );
	if(aType == EEventKeyDown)
	{
	iFreeScrollPeriodic->Cancel();
	}
	else if(aType == EEventKey)
		{
			switch(aKeyEvent.iCode)
				{
				case EKeyUpArrow:
				case EKeyDownArrow:
				case EKeyRightArrow:
				case EKeyLeftArrow:
				iPositionTracking = EFalse;
				TCoordinate direction (
						(aKeyEvent.iCode == EKeyUpArrow) ? 1 :
						(aKeyEvent.iCode == EKeyDownArrow) ? -1 : 0,
						(aKeyEvent.iCode == EKeyRightArrow) ? 1 :
						(aKeyEvent.iCode == EKeyLeftArrow) ? -1 : 0
						);
				const TStation* newSelectedStation = NULL;
				if(view->iZoomLevel >= kZoomLevelDisplayStations)
					{
					if(view->iSelectedStation)
						newSelectedStation = ( FindNextVisibleStationL(view->iSelectedStation, direction) );
					else if(iVisibleStations.Count() != 0)
						newSelectedStation = ( iVisibleStations[0] );
					if(newSelectedStation) // no need to move the map
						{
							view->iSelectedStation = ( newSelectedStation );
							iFreeScrollPeriodic->Cancel();
						}
					}
				if(view->iZoomLevel < kZoomLevelDisplayStations || !newSelectedStation) // we need to move the map in the correct direction
					{
					TPoint direction (
							(aKeyEvent.iCode == EKeyRightArrow) ? -1 :
							(aKeyEvent.iCode == EKeyLeftArrow) ? +1 : 0,
							(aKeyEvent.iCode == EKeyUpArrow) ? +1 :
							(aKeyEvent.iCode == EKeyDownArrow) ? -1 : 0
							);					
					iFreeScrollSpeed.SetXY(
							200*100*direction.iX,
							200*100*direction.iY
							);
					iOrigFreeScrollSpeed = iFreeScrollSpeed;
					if(!iFreeScrollPeriodic->IsActive() )
						{
						iFreeScrollCallbackTime.UniversalTime();
						iFreeScrollFunction = &NoDeceleration;
						iFreeScrollPeriodic->Cancel();
						iFreeScrollPeriodic->Start( 0, KMaxTInt, TCallBack(&MemFunDelegate<CPublicTransportMapContainer, &CPublicTransportMapContainer::FreeScrollCallback>, this) );
						}

					}
				view->UpdateTitle();
		    	DrawToBackBuffer();
				DrawDeferred();
				return EKeyWasConsumed;
				break;
				}
		}
		else if(aType == EEventKeyUp)
		{
		iFreeScrollFunction = &ExpDeceleration;
		}
	
		if(aType == EEventKey)
			{
			switch(aKeyEvent.iScanCode)
				{
				case 167:
					if(view->iSelectedStation && view->iSelectedStation->iStationNumber.Length() >= 4)
						{
						TBuf8<128> buf;
						StoreCustomMessageParamL(buf, _L8("id"), _L8("%S"), &view->iSelectedStation->iStationNumber);
						iAvkonViewAppUi->ActivateLocalViewL(TUid::Uid( ESingaporeBusServicesArrivalTimeViewId ), TUid::Uid(0), buf);
						}
					return EKeyWasConsumed;
					break;
				case '5':
					if (view->iDisplayServiceKeys.Count())
						{
						view->iCurrentDisplayServiceKey = (view->iCurrentDisplayServiceKey + 1) % view->iDisplayServiceKeys.Count();
						LoadCurrentDisplayServiceL();
						}
			    	DrawToBackBuffer();
					DrawDeferred();
					return EKeyWasConsumed;
					break;
				case '0':
					if(doc->iPositioningStatus == CSingaporeBusDocument::PS_FOUND)
						CenterMapOn(doc->iPosition);
			    	DrawToBackBuffer();
			    	iPositionTracking = ETrue;
			    	DrawDeferred();
					return EKeyWasConsumed;
					break;
				case EStdKeyNkpAsterisk: case '*': case EStdKeyEnter:
				case EStdKeyHash: case '#': case EStdKeyBackspace:
					TInt newZoomLevel =
						(aKeyEvent.iScanCode == EStdKeyNkpAsterisk || aKeyEvent.iScanCode == '*' || aKeyEvent.iScanCode == EStdKeyEnter) ? Min( view->iZoomLevel + 1, ZoomLevels() - 1 ) :
						(aKeyEvent.iScanCode == EStdKeyHash || aKeyEvent.iScanCode == '#' || aKeyEvent.iScanCode == EStdKeyBackspace) ? Max( view->iZoomLevel - 1, 0 ) : view->iZoomLevel;
					ZoomTo(newZoomLevel);
			    	DrawToBackBuffer();
					DrawDeferred();
					return EKeyWasConsumed;
				}
		}
	if(aType == EEventKeyDown)
		{
		switch(aKeyEvent.iScanCode)
			{
			case EStdKeyRightShift: case EStdKeyLeftShift:
				view->MenuBar()->SetContextMenuTitleResourceId(R_PUBLIC_TRANSPORT_MAP_CONTAINER_MARK_CONTEXT_MENU);
				view->MenuBar()->TryDisplayContextMenuBarL();
				return EKeyWasConsumed;
				break;
			}		
		}
				
	if ( iFocusControl != NULL
		&& iFocusControl->OfferKeyEventL( aKeyEvent, aType ) == EKeyWasConsumed )
		{
		return EKeyWasConsumed;
		}
	return CCoeControl::OfferKeyEventL( aKeyEvent, aType );
	}
				
// [[[ begin generated function: do not modify
/**
 *	Initialize each control upon creation.
 */				
void CPublicTransportMapContainer::InitializeControlsL()
	{
	
	}
// ]]] end generated function

/** 
 * Handle global resource changes, such as scalable UI or skin events (override)
 */
void CPublicTransportMapContainer::HandleResourceChange( TInt aType )
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	CCoeControl::HandleResourceChange( aType );
	SetRect( iAvkonViewAppUi->View( TUid::Uid( EPublicTransportMapContainerViewId ) )->ClientRect() );
	// [[[ begin generated region: do not modify [Generated Contents]
	// ]]] end generated region [Generated Contents]
	
	}


TUint32 isqrt(TUint32 x)
{
    register TUint32 op, res, one;

    op = x;
    res = 0;

    /* "one" starts at the highest power of four <= than the argument. */
    one = 1 << 30;  /* second-to-top bit set */
    while (one > op) one >>= 2;

    while (one != 0) {
        if (op >= res + one) {
            op -= res + one;
            res += one << 1;  // <-- faster than 2 * one
        }
        res >>= 1;
        one >>= 2;
    }
    return res;
}

static TInt TLinearOrder_TPtrC8(const TPtrC8& left, const TPtrC8& right)
	{
	return left.Compare(right);
	}


void CPublicTransportMapContainer::DrawToBackBuffer()
	{
	TRAPD(err, DrawToBackBufferCore());
	if(err != KErrNone)
		PrintNoteL(_L("DrawToBackBuffer:Error %d"), err);
	}

void CPublicTransportMapContainer::DrawToBackBufferCore()
	{
#ifndef __SERIES60_3X__ // Symbian^3 does not define that macro
	;
#else
	DrawToCore(iBackBufferContext.Get());
#endif
	}
void CPublicTransportMapContainer::DrawToCore(CBitmapContext* aGc) const
	{
	static TInt startDraw = 0;
	static TInt endDraw = 0;
	static TInt bgColor = 0;
	TTime timeStartFrame;
	timeStartFrame.UniversalTime();
	static TInt maxTimeFrame = 0;
	static TInt accTimeFrame = 0;
	static TInt accCountFrames = 0;

	
	++startDraw;
	
	
	CBitmapContext& gc = *aGc;
	TRect aRect( Rect() );
	

	gc.SetBrushColor(KRgbWhite);
	gc.Clear();

	CPublicTransportMapContainerView* view = (CPublicTransportMapContainerView*)iAvkonViewAppUi->View( TUid::Uid( EPublicTransportMapContainerViewId ) );
	CSingaporeBusDocument* doc = (CSingaporeBusDocument*)CEikonEnv::Static()->EikAppUi()->Document();
	
	
#if defined(MAPQUEST)
	int begtilex = (view->iOrig.Longitude() - (-180)) / (kTilesResolutions[view->iZoomLevel] * iTilesSize.iWidth);
	int begdrawx = (-180 - view->iOrig.Longitude()) / kTilesResolutions[view->iZoomLevel] + begtilex * iTilesSize.iWidth;
	int endtilex = begtilex + (Rect().Width() - begdrawx - 1)/iTilesSize.iWidth;
	int begtiley = Lat2TileY(view->iOrig.Latitude(), 11 + view->iZoomLevel);
	int endtiley = Lat2TileY(view->iOrig.Latitude() - Rect().Height() * YScale(view->iOrig) * kTilesResolutions[view->iZoomLevel], 11 + view->iZoomLevel);	
	int begdrawy = (view->iOrig.Latitude() - TileY2Lat(begtiley, 11 + view->iZoomLevel)) / (kTilesResolutions[view->iZoomLevel] * YScale(view->iOrig));
#elif defined(ONEMAP)
	TENCoordinate origENCoord = CnvLL2EN(view->iOrig.Latitude(), view->iOrig.Longitude());
	int begtilex = (origENCoord.iEasting - kTileOrigE) / (kTilesResolutionsSVY21[view->iZoomLevel] * iTilesSize.iWidth);
	int begtiley = (kTileOrigN - origENCoord.iNorthing) / (kTilesResolutionsSVY21[view->iZoomLevel] * iTilesSize.iHeight);
	int begdrawx = (kTileOrigE - origENCoord.iEasting) / kTilesResolutionsSVY21[view->iZoomLevel] + begtilex * iTilesSize.iWidth;
	int begdrawy =  - ((kTileOrigN - origENCoord.iNorthing) / kTilesResolutionsSVY21[view->iZoomLevel] - begtiley * iTilesSize.iHeight);
	int endtilex = begtilex + (Rect().Width() - begdrawx - 1)/iTilesSize.iWidth;
	int endtiley = begtiley  + (Rect().Height() - begdrawy  - 1)/iTilesSize.iHeight;	
#endif
	
	int itilex, itiley, idrawx, idrawy;
	for(itilex = begtilex, idrawx = begdrawx ; idrawx < aRect.Width() ; itilex++, idrawx += iTilesSize.iWidth)
		for(itiley = begtiley, idrawy = begdrawy ; idrawy < aRect.Height()  ; itiley++, idrawy += iTilesSize.iHeight )
		{
		CFbsBitmap* bitmap = doc->iMapTileServer->GetTileBitmap(itilex, itiley, view->iZoomLevel);
		if(bitmap)
			gc.BitBlt(TPoint(idrawx, idrawy), bitmap);
		else
			{
			/*const TRgb textColor (141, 64, 141);
			TPtrC text;
			TRect rect(TPoint(idrawx, idrawy), iTilesSize);
			TInt baseline = rect.Height() /2 + iMapFont->FontMaxAscent()/2;
			gc.UseFont(iMapFont);
			gc.SetPenColor( textColor );
			gc.SetBrushStyle( CGraphicsContext::ENullBrush );
			TInt i;
			for(i = 0 ; i < iTiles.Count() && !(iTiles[i]->iX == itilex && iTiles[i]->iY == itiley && iTiles[i]->iZoom == view->iZoomLevel) ; ++i);
			if(i == iTiles.Count())
				{
				gc.DrawText(_L("Not queried!"), rect, baseline, CGraphicsContext::ECenter, 0);				
				}
			else
				{
				switch(iTiles[i]->iStatus)
					{
					case CTileInfo::EError:
						gc.DrawText(_L("Error"), rect, baseline, CGraphicsContext::ECenter, 0);
						break;
					case CTileInfo::EPending:
						gc.DrawText(_L("Requesting..."), rect, baseline, CGraphicsContext::ECenter, 0);
						break;
					}
				}*/
			}
		}


	// ================================
	// Draw bus paths
	// ================================
	for( TInt i = 0 ; i < doc->iServicePaths.Count() ; ++i )
		{
		const TServicePath* servicePath = &doc->iServicePaths[i];
		const TDesC8& serviceKey = servicePath->iServiceKey;
		TPtrC8 serviceName = serviceKey.Left( serviceKey.Locate(' ') );
				
//		const TRgb pathColor (206, 111, 216, 127);
		const TRgb pathColor (141, 64, 141, 127);
		const TRgb pathTextColor (141, 64, 141);
		
		gc.UseFont(iMapFont);		
		
		TPoint point, prevPoint;
		TInt distFromLastArrow = 0;
		TInt distFromLastBusLabel = 0;
		const TInt distBetweenArrows = aRect.Size().iWidth / 3, distBetweenBusLabels = aRect.Size().iWidth / 3;
		
		
		HBufC* wServiceName = narrowToWideLC(serviceName);
		const TInt busLabelWidth = iMapFont->TextWidthInPixels(*wServiceName);
		TBool pathReset = EFalse;
		TCoordinate prevCoordinate;
		for( TInt j = servicePath->iPathBeg  ; j < servicePath->iPathEnd ; ++j )
			{
				const TCoordinate& coordinate = doc->iServicePathsCoordinates[j];
				point.SetXY(
						(coordinate.Longitude() - view->iOrig.Longitude()) / kTilesResolutions[view->iZoomLevel],
						(view->iOrig.Latitude() - coordinate.Latitude()) / (kTilesResolutions[view->iZoomLevel]*YScale(view->iOrig))
						);
				if(coordinate.Longitude() == 0.0 && coordinate.Latitude() == 0.0)
					pathReset = ETrue;
				else if (pathReset)
					{
					gc.MoveTo(point);
					distFromLastArrow = 0;
					distFromLastBusLabel = distBetweenBusLabels/2;
					pathReset = EFalse;
					}
				else
					{
					
					if(	
						(prevPoint.iX < 0 && point.iX < 0) ||
						(prevPoint.iY < 0 && point.iY < 0) ||
						(prevPoint.iX >= aRect.Width() && point.iX >= aRect.Width()) ||
						(prevPoint.iY >= aRect.Height() && point.iY >= aRect.Height())
					  )
						{
						// line not visible
						distFromLastArrow = 0;
						distFromLastBusLabel = distBetweenBusLabels/2;						
						}
					else if(prevPoint == point)
						{
						// do nothing
						}
					else
						{
					
						gc.SetPenSize( TSize(5, 5) );
						gc.SetPenColor( pathColor );
						gc.DrawLineTo(point);
						{
						
							const TInt segmentLen = isqrt( (point.iX - prevPoint.iX)*(point.iX - prevPoint.iX) + (point.iY - prevPoint.iY)*(point.iY - prevPoint.iY) );
							
							if(! (distBetweenBusLabels - distFromLastBusLabel > 0 && distBetweenBusLabels - distFromLastBusLabel <= segmentLen ))
								distFromLastBusLabel += segmentLen;
							else
								{
								for( TInt segmentPos = distBetweenBusLabels - distFromLastBusLabel ; segmentPos > 0 && segmentPos <= segmentLen ; segmentPos += distBetweenBusLabels )
									{
									if(1 == 0) // display service number on the path
										{
										const TPoint busLabelPoint (prevPoint.iX + (point.iX - prevPoint.iX)*segmentPos/segmentLen, prevPoint.iY + (point.iY - prevPoint.iY)*segmentPos/segmentLen);																			
										const TInt fontMaxHeight = iMapFont->FontMaxHeight();
										TRect textBox(busLabelPoint.iX - busLabelWidth/2, busLabelPoint.iY - fontMaxHeight/2, busLabelPoint.iX + busLabelWidth/2, busLabelPoint.iY + fontMaxHeight/2);
										TInt baseline = textBox.Height() /2 + iMapFont->FontMaxAscent()/2;
										gc.SetPenColor( pathTextColor );
										gc.SetBrushStyle( CGraphicsContext::ENullBrush );
										gc.DrawText(*wServiceName, textBox, baseline, CGraphicsContext::ECenter, 0);
										}
									distFromLastBusLabel = segmentLen - segmentPos;							
									}
								}
							
													
							if(! (distBetweenArrows - distFromLastArrow > 0 && distBetweenArrows - distFromLastArrow <= segmentLen ))
								distFromLastArrow += segmentLen;
							else
								{
								for( TInt segmentPos = distBetweenArrows - distFromLastArrow ; segmentPos > 0 && segmentPos <= segmentLen ; segmentPos += distBetweenArrows )
									{
										const TInt arrowAlpha = 1, arrowBranchLen = 20 /* px */;
										const TReal64
											segmentLong = coordinate.Longitude() - prevCoordinate.Longitude(),
											segmentLat = -coordinate.Latitude() + prevCoordinate.Latitude()
											;
										const TSize denArrowBranch1(
												(-arrowAlpha*segmentLong - segmentLat)/kTilesResolutions[5],
												(segmentLong - arrowAlpha*segmentLat)/kTilesResolutions[5]
												);
										const TSize denArrowBranch2(
												(-arrowAlpha*segmentLong + segmentLat)/kTilesResolutions[5],
												(-segmentLong - arrowAlpha*segmentLat)/kTilesResolutions[5]
												);
										const TInt denArrowBranchLen = Max(1, isqrt(denArrowBranch1.iHeight*denArrowBranch1.iHeight+denArrowBranch1.iWidth*denArrowBranch1.iWidth));
										const TSize arrowBranch1(
												denArrowBranch1.iWidth*arrowBranchLen/denArrowBranchLen,
												denArrowBranch1.iHeight*arrowBranchLen/denArrowBranchLen
												);
										const TSize arrowBranch2(
												denArrowBranch2.iWidth*arrowBranchLen/denArrowBranchLen,
												denArrowBranch2.iHeight*arrowBranchLen/denArrowBranchLen
												);										
										const TPoint arrowPoint (prevPoint.iX + (point.iX - prevPoint.iX)*segmentPos/segmentLen, prevPoint.iY + (point.iY - prevPoint.iY)*segmentPos/segmentLen);																			
										const TPoint pointArrow[] =
										{
											arrowPoint+arrowBranch1,
											arrowPoint,
											arrowPoint+arrowBranch2
										};
										//gc.DrawPolyLine(pointArrow, 3);
										gc.SetPenSize( TSize(0, 0) );
										gc.SetBrushColor( pathColor );
										gc.SetBrushStyle( CGraphicsContext::ESolidBrush );
										gc.DrawPolygon(pointArrow, 3);
										distFromLastArrow = segmentLen - segmentPos;							
									}
								}
						}
					}

					gc.MoveTo(point);					
					}
				prevPoint = point;
				prevCoordinate = coordinate;
			
			}
		gc.DiscardFont();
		CleanupStack::PopAndDestroy(wServiceName);
		}
		
		
		
		
		
		// ================================
		// Draw bus stops
		// ================================
		
		if(view->iZoomLevel >= kZoomLevelDisplayStations)
				{
							
				gc.UseFont(iMapFont);
				TBuf<128> descStationNumber;
				TBool selectedStationIsVisible = EFalse;
				for(TInt i = 0 ; i < iVisibleStations.Count() ; ++i)
					{

					selectedStationIsVisible = selectedStationIsVisible || (iVisibleStations[i] == view->iSelectedStation);
					const TStation* station = 
						(iVisibleStations[i] == view->iSelectedStation) ? iVisibleStations[iVisibleStations.Count() - 1] :
						((i == iVisibleStations.Count() - 1) && selectedStationIsVisible) ? view->iSelectedStation :
						iVisibleStations[i];
					
					const TInt
						stationX = (station->iCoord.Longitude() - view->iOrig.Longitude()) / kTilesResolutions[view->iZoomLevel],
						stationY = (view->iOrig.Latitude() - station->iCoord.Latitude()) / (kTilesResolutions[view->iZoomLevel]*YScale(view->iOrig));

					if(station == view->iSelectedStation)
						{
						gc.SetPenSize( TSize(5, 5) );
						gc.SetPenColor( TRgb(255, 0, 0, 127) );
						gc.SetPenStyle( CGraphicsContext::ESolidPen );
						gc.SetBrushStyle( CGraphicsContext::ENullBrush );
						
						TSize busStationIconSize = iBusStationIcon->Bitmap()->SizeInPixels();
						TSize ellipseSize = busStationIconSize;
						TRect ellipseRect(stationX - ellipseSize.iWidth/2, stationY - ellipseSize.iHeight/2, stationX + ellipseSize.iWidth/2, stationY + ellipseSize.iHeight/2);
						ellipseRect.Grow(10, 10);
						gc.DrawEllipse(ellipseRect);				
						}
					
					if(iBusStationIcon.Get() && iMrtStationIcon.Get())
						{
						
						TSize size = iBusStationIcon->Bitmap()->SizeInPixels();
						TRect rect( TPoint(stationX - size.iWidth/2, stationY - size.iHeight/2), size);
						
						if(doc->iServicePaths.Count())
							{
								const TDesC8& serviceKey = doc->iServicePaths[0].iServiceKey;
								TInt i;
								for(i = station->iServicesBeg ; (i < station->iServicesEnd) && (serviceKey != doc->iStationServiceKeys[i]) ; ++i);
								if(i < station->iServicesEnd)
									{
									const TRgb solidPathColor (141, 64, 141);
									gc.SetPenSize( TSize(3,3) );
									gc.SetPenStyle( CGraphicsContext::ESolidPen );
									gc.SetPenColor(solidPathColor);
									gc.SetBrushStyle( CGraphicsContext::ENullBrush );
									TRect halo = rect;
									halo.Grow(4, 4);
									//halo.iBr.iX --; halo.iBr.iY --; // to ensure that the halo is centered on the bus station icon. This is due to the fact that the penSize > 1
									gc.DrawRect( halo );
									}
							}

						if(station->iStationNumber.Length() < 4)
							{
							gc.BitBlt(rect.iTl, iMrtStationIcon->Bitmap(), size);
							}
						else
							{
							//gc.BitBlt(rect.iTl, iBusStationIcon->Bitmap(), size);
							TRect sourceRect(TPoint(0,0), iBusStationIcon->Bitmap()->SizeInPixels());
							gc.SetBrushStyle(CGraphicsContext::ENullBrush);
							gc.BitBltMasked (rect.iTl, iBusStationIcon->Bitmap(), sourceRect, iBusStationIcon->Mask(), ETrue);
							}
						
						TBool favoriteStation = EFalse;
						for(TInt i = 0 ; i < doc->iFavorites.Count() && !favoriteStation; ++i)
							favoriteStation = ((doc->iFavorites[i])->Find(station->iStationNumber) != NULL);

						if(iStarIcon.Get() && favoriteStation)
							{
							TRect starRect(TPoint(0,0), iStarIcon->Bitmap()->SizeInPixels());
							gc.SetBrushStyle(CGraphicsContext::ENullBrush);
							gc.BitBltMasked(TPoint(stationX - size.iWidth, stationY - size.iHeight), iStarIcon->Bitmap(), starRect, iStarIcon->Mask(), ETrue);
							}

						if(iFlagOrigIcon.Get() && doc->iOriginStation == station)
							{
							TSize flagSize = iFlagOrigIcon->Bitmap()->SizeInPixels();
							TRect flagRect(TPoint(0,0), iFlagOrigIcon->Bitmap()->SizeInPixels());
							gc.SetBrushStyle(CGraphicsContext::ENullBrush);
							gc.BitBltMasked(TPoint(stationX + size.iWidth/3, stationY - size.iHeight), iFlagOrigIcon->Bitmap(), flagRect, iFlagOrigIcon->Mask(), ETrue);							
							}
						
						if(iFlagDestIcon.Get() && doc->iDestinationStation == station)
							{
							TSize flagSize = iFlagDestIcon->Bitmap()->SizeInPixels();
							TRect flagRect(TPoint(0,0), iFlagDestIcon->Bitmap()->SizeInPixels());
							gc.SetBrushStyle(CGraphicsContext::ENullBrush);
							gc.BitBltMasked(TPoint(stationX + size.iWidth/3, stationY - size.iHeight), iFlagDestIcon->Bitmap(), flagRect, iFlagDestIcon->Mask(), ETrue);							
							}
						
						
						}
					
						
						
					if(station == view->iSelectedStation)
						{
						descStationNumber.Copy(station->iStationNumber);
						TInt descStationWidth = iMapFont->TextWidthInPixels(descStationNumber);
						TSize busStationIconSize = iBusStationIcon->Bitmap()->SizeInPixels();
						const TInt horizontalMargin = 5, verticalMargin = 5;
						const TInt fontMaxHeight = iMapFont->FontMaxHeight();
						TRect textBox(stationX - descStationWidth/2 - horizontalMargin, stationY + busStationIconSize.iHeight, stationX + descStationWidth/2 + horizontalMargin, stationY + busStationIconSize.iHeight + fontMaxHeight + verticalMargin*2);
						TInt baseline = textBox.Height() /2 + iMapFont->FontMaxAscent()/2;
						if(station == view->iSelectedStation)
							{
							gc.SetPenColor( TRgb(255, 0, 0) );
							}
						else
							{
							gc.SetPenColor( TRgb(100, 100, 100, 127) );
							}
						gc.SetBrushStyle( CGraphicsContext::ENullBrush );
							
						gc.DrawText(descStationNumber, textBox, baseline, CGraphicsContext::ECenter, 0);

						}
					}
				
				gc.DiscardFont();
				}
		else
			{
			// we just display the flags
			const TStation* stations[] = { doc->iOriginStation, doc->iDestinationStation };
			for(TInt i = 0 ; i < sizeof(stations)/sizeof(stations[0]) ; ++i)
				{
				const TStation* station = stations[i];
				if(!station) continue;
				const TInt
					stationX = (station->iCoord.Longitude() - view->iOrig.Longitude()) / kTilesResolutions[view->iZoomLevel],
					stationY = (view->iOrig.Latitude() - station->iCoord.Latitude()) / (kTilesResolutions[view->iZoomLevel]*YScale(view->iOrig));
				if(iFlagOrigIcon.Get() && doc->iOriginStation == station)
					{
					TSize flagSize = iFlagOrigIcon->Bitmap()->SizeInPixels();
					TRect flagRect(TPoint(0,0), iFlagOrigIcon->Bitmap()->SizeInPixels());
					gc.SetBrushStyle(CGraphicsContext::ENullBrush);
					gc.BitBltMasked(TPoint(stationX , stationY - flagRect.Height()), iFlagOrigIcon->Bitmap(), flagRect, iFlagOrigIcon->Mask(), ETrue);							
					}
				
				if(iFlagDestIcon.Get() && doc->iDestinationStation == station)
					{
					TSize flagSize = iFlagDestIcon->Bitmap()->SizeInPixels();
					TRect flagRect(TPoint(0,0), iFlagDestIcon->Bitmap()->SizeInPixels());
					gc.SetBrushStyle(CGraphicsContext::ENullBrush);
					gc.BitBltMasked(TPoint(stationX, stationY - flagRect.Height()), iFlagDestIcon->Bitmap(), flagRect, iFlagDestIcon->Mask(), ETrue);							
					}			
				}
			
			
			}
		
		// draw steps label
		gc.UseFont(iMapFont);
		if(view->iDisplayRouteSteps)
		{
		}
		gc.DiscardFont();
				
		
		
		// ================================
		// Draw bus label
		// ================================
	if(doc->iServicePaths.Count())
	{
		const TDesC8& serviceKey = doc->iServicePaths[0].iServiceKey;
		TPtrC8 serviceName = serviceKey.Left( serviceKey.Locate(' ') );		
		HBufC* wServiceName = narrowToWideLC(serviceName);
		const TRgb pathTextColor (141, 64, 141);
		TInt textWidth = iMapFont->TextWidthInPixels(*wServiceName);
		const TInt horizontalMargin = 2, verticalMargin = 2;
		const TInt fontMaxHeight = iMapFont->FontMaxHeight();
		iServiceNameRect.SetRect(10, 10, 10 + textWidth + horizontalMargin*2, 10 + fontMaxHeight + verticalMargin*2);
		TInt baseline = iServiceNameRect.Height() /2 + iMapFont->FontMaxAscent()/2;
	
		gc.UseFont(iMapFont);
		gc.SetPenColor( KRgbWhite );
		gc.SetBrushColor( pathTextColor );
		gc.SetBrushStyle( CGraphicsContext::ESolidBrush );
		gc.DrawText(*wServiceName, iServiceNameRect, baseline, CGraphicsContext::ECenter, 0);
		gc.DiscardFont();
		CleanupStack::PopAndDestroy(wServiceName);
	}
	
		
	
	{
	
	// ================================
	// Draw current position
	// ================================
	
	CSingaporeBusDocument* doc = (CSingaporeBusDocument*)CEikonEnv::Static()->EikAppUi()->Document();
	if(doc->iPositioningStatus == CSingaporeBusDocument::PS_FOUND)
		{
		const TPoint currentPos
			(
				(doc->iPosition.Longitude() - view->iOrig.Longitude()) / kTilesResolutions[view->iZoomLevel],
				(view->iOrig.Latitude() - doc->iPosition.Latitude()) / (kTilesResolutions[view->iZoomLevel]*YScale(view->iOrig))
			);
		// halo
		{
		TRect currentRect( currentPos, TSize(0,0) );
		const TInt earthMeanRadius = 6371000; // in m
		TInt rectSize = Max(5, doc->iPositionAccuracy/(kTilesResolutions[view->iZoomLevel]*earthMeanRadius*KPi/180));
		currentRect.Grow(rectSize, rectSize);
		
		gc.SetPenStyle(CGraphicsContext::ESolidPen); gc.SetPenColor(KRgbRed); gc.SetPenSize( TSize(1, 1) ); 
		TRgb bgColor(KRgbRed); bgColor.SetAlpha(64);
		gc.SetBrushStyle( CGraphicsContext::ESolidBrush ); gc.SetBrushColor( bgColor );
		gc.DrawEllipse(currentRect);
		}
		
		//center
#ifndef __SERIES60_3X__
		if(doc->iMagnetometerCalibrationLevel != 0 && doc->iMagneticNorthDataError == KErrNone)
			{
			TInt angle = 90 - doc->iMagneticNorthData.iAngleFromMagneticNorth;
			TReal cosA, sinA;
			Math::Cos(cosA, angle*KPi/180);
			Math::Sin(sinA, angle*KPi/180);
			//cosA = FastCos(angle);
			//sinA = FastSin(angle);
			const TReal sqrt2 = 1.4142135623730950488016887242097;
			TRect circle( currentPos, TSize(0,0) );
			circle.Grow(aRect.Height()/24, aRect.Height()/24);
			TPoint polygonPoints[] =
			{
					circle.Center(), 
					circle.Center() + TPoint( circle.Height()*sqrt2*(- cosA - sinA)/4, -circle.Height()*sqrt2*(- sinA + cosA)/4 ),
					circle.Center() + TPoint( circle.Height()*(cosA)/2, -circle.Height()*(sinA)/2 ),
					circle.Center() + TPoint( circle.Height()*sqrt2*(- cosA + sinA)/4, -circle.Height()*sqrt2*(- sinA - cosA)/4 ),
					circle.Center()
			};
			gc.SetBrushStyle(CGraphicsContext::ESolidBrush); gc.SetBrushColor( KRgbRed );
			gc.SetPenStyle(CGraphicsContext::ENullPen);
			gc.DrawPolygon(polygonPoints, sizeof(polygonPoints)/sizeof(polygonPoints[0]));
			}
		else
#endif
			{
			TRect currentRect( currentPos, TSize(0,0) );
			currentRect.Grow(5, 5);
			gc.SetPenStyle(CGraphicsContext::ENullPen);
			gc.SetBrushColor( KRgbRed );
			gc.SetBrushStyle( CGraphicsContext::ESolidBrush );
			gc.DrawEllipse(currentRect);
			}
	

		}
	
	// ================================
	// Draw previous known positions
	// ================================
	
	gc.SetPenStyle( CGraphicsContext::ENullPen  );
	gc.SetBrushColor( TRgb(255, 0, 0) );
	gc.SetBrushStyle( CGraphicsContext::ESolidBrush );
	
	for(TInt i = 0 ; i < doc->iPrevGPSPositions.Count() ; ++i)
		{
		const TPoint pos
			(
				(doc->iPrevGPSPositions[i].Longitude() - view->iOrig.Longitude()) / kTilesResolutions[view->iZoomLevel],
				(view->iOrig.Latitude() - doc->iPrevGPSPositions[i].Latitude()) / (kTilesResolutions[view->iZoomLevel]*YScale(view->iOrig))
			);
		const TInt posSize = 2*(i - doc->iPrevGPSPositions.Count() + 5);
		const TRect rect(
				pos.iX - posSize/2,
				pos.iY - posSize/2,
				pos.iX + posSize/2,
				pos.iY + posSize/2
				);
		gc.DrawEllipse(rect);
		}
	
	}
	
	{
		// ================================
		// Draw zoom controls
		// ================================
		const TInt margin = 4, thickness = 4;
		const TRgb pathTextColor (141, 64, 141);
		TInt baseline = iServiceNameRect.Height() /2 + iMapFont->FontMaxAscent()/2;
		if(!iZoomInRect.IsEmpty() && iZoomInIcon.Get())
			{
			TRect rect( TPoint(0,0), iZoomInRect.Size());
			gc.SetBrushStyle(CGraphicsContext::ENullBrush);
			gc.BitBltMasked(iZoomInRect.iTl, iZoomInIcon->Bitmap(), rect, iZoomInIcon->Mask(), ETrue);
			}
		if(!iZoomOutRect.IsEmpty() && iZoomOutIcon.Get())
			{
			TRect rect( TPoint(0,0), iZoomOutRect.Size());
			gc.SetBrushStyle(CGraphicsContext::ENullBrush);
			gc.BitBltMasked(iZoomOutRect.iTl, iZoomOutIcon->Bitmap(), rect, iZoomOutIcon->Mask(), ETrue);
			}
		if(!iCenterMapOnPositionRect.IsEmpty() && iCenterMapOnPositionIcon.Get())
			{
			TRect rect( TPoint(0,0), iCenterMapOnPositionRect.Size());
			gc.SetBrushStyle(CGraphicsContext::ENullBrush);
			gc.BitBltMasked(iCenterMapOnPositionRect.iTl, iCenterMapOnPositionIcon->Bitmap(), rect, iCenterMapOnPositionIcon->Mask(), ETrue);
			}	
		if(!iRefreshPositionRect.IsEmpty() && iRefreshPositionIcon.Get())
			{
			TRect rect( TPoint(0,0), iRefreshPositionRect.Size());
			gc.SetBrushStyle(CGraphicsContext::ENullBrush);
			gc.BitBltMasked(iRefreshPositionRect.iTl, iRefreshPositionIcon->Bitmap(), rect, iRefreshPositionIcon->Mask(), ETrue);
			}	


		
				
		// ================================
		// Draw memory usage
		// ================================
		/*
		{
	   TInt freeRam = 0;
	   HAL::Get( HAL::EMemoryRAMFree, freeRam );
	   User::AllocSize(aft);
		gc.UseFont(iMapFont);
		_LIT(kFormat,"bef%d, aft%d, %d");
		TBuf<128> textToDraw;
		textToDraw.Format(kFormat, bef, aft-bef, freeRam);
		gc.DrawText(textToDraw, TPoint(0, 20));
		gc.DiscardFont();
		gc.SetBrushColor( TRgb(255, 255, 255, 127) );
		gc.SetBrushStyle( CGraphicsContext::ESolidBrush );
		gc.SetPenSize( TSize(5, 5) );
		}*/

		// ================================
		// Draw FPS
		// ================================
		if(1 == 0)
		{
		TTime timeEndFrame;
		timeEndFrame.UniversalTime();
		
		if(timeEndFrame.MicroSecondsFrom(timeStartFrame) > maxTimeFrame)
			maxTimeFrame = timeEndFrame.MicroSecondsFrom(timeStartFrame).Int64();
		accTimeFrame += timeEndFrame.MicroSecondsFrom(timeStartFrame).Int64();
		accCountFrames++;


		_LIT(kFormat,"cur: %d ms, max: %d ms, avg: %d ms");
		TBuf<128> textToDraw;
		textToDraw.Format(kFormat, (TInt)(timeEndFrame.MicroSecondsFrom(timeStartFrame).Int64()/1000), maxTimeFrame/1000, (accTimeFrame/accCountFrames)/1000);
		gc.UseFont(iMapFont);
		gc.SetPenColor( KRgbBlack );
		gc.DrawText(textToDraw, TPoint(0, 20));
		
		if(iVisibleStations.Count() == 0) iZeroVisibleStationsCount++;
		if(!iBusStationIcon.Get()) iEmptyIconCount++;
		
		iDrawBackThreadId = RThread().Handle();
		TRgb aColor;
		iBackBuffer->GetPixel(aColor, TPoint(0,0));
		textToDraw.Format(_L("msm: %d, 0pt: %d %d %d, me: %d"), iCountMismatch, aColor.Red(), aColor.Green(), aColor.Blue(), iEmptyIconCount);
		gc.DrawText(textToDraw, TPoint(0, 40));

		gc.DiscardFont();

		
		}
		
		// ================================
		// Draw stuff
		// ================================
		if(1 == 0)
		{
		gc.UseFont(iMapFont);
		gc.SetPenColor( KRgbBlack );
		gc.DrawText(_L("HELLO TOO"), iZoomInRect.iTl + TPoint(100, 50));
		gc.DiscardFont();
		}
		
		

		}
	++endDraw;
	
			
	}

/**
 *	Draw container contents.
 */				
void CPublicTransportMapContainer::Draw( const TRect& aRect ) const
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);

	if(1 == 0) // we do not need to clear the screen since we use double buffer
		{
	// [[[ begin generated region: do not modify [Generated Contents]
	CWindowGc& gc = SystemGc();
	gc.Clear( aRect );
	
	// ]]] end generated region [Generated Contents]
		}

	static TInt countMismatch = 0;
	if(0==0)
		{
		TRgb color;
		const TRgb kBusStationColor(8, 162, 206);		
		iBackBuffer->GetPixel(color, TPoint(0,0));
		if(color != kBusStationColor) iCountMismatch++;
		}


		
	iDrawThreadId = RThread().Handle();

	CWindowGc& gc = SystemGc();

#ifndef __SERIES60_3X__ // Symbian^3 does not define that macro
	DrawToCore(&gc);
#else
	gc.BitBlt(TPoint(0, 0), iBackBuffer.Get());
#endif
	
	

	
#ifndef __SERIES60_3X__ // Symbian^3 does not define that macro
/*	TInt err = iCoeEnv->WsSession().Finish(); // we need this for certain reasons in Symbian^3 http://library.developer.nokia.com/topic/GUID-E35887BB-7E58-438C-AA27-97B2CDE7E069/GUID-D93978BE-11A3-5CE3-B110-1DEAA5AD566C.html 
	if(err != KErrNone)
		iCountMismatch = err;*/
#endif

	
	if(1==0)
		{
		TPoint absPosition = Window().AbsPosition();
		TRgb absColor;
		static TInt countFinalMismatch = 0;
		{
		((CBitmapDevice*)gc.Device())->GetPixel(absColor, absPosition);
		if(absColor != KRgbGray) countFinalMismatch++;
		}
		
		
		
		gc.UseFont(iMapFont);
		gc.SetPenColor( KRgbBlack );
		TBuf<128> text;
		text.Format(_L("HELLO: %d, %d, %d, %d, %d, %d, %d"), countMismatch, countFinalMismatch, absColor.Red(), absColor.Green(), absColor.Blue(), absPosition.iX, absPosition.iY);
		gc.DrawText(text, iZoomInRect.iTl + TPoint(100, 30));
		gc.DiscardFont();
		}

	
	}



void CPublicTransportMapContainer::CenterMapOn(const TCoordinate& aCoord)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	CPublicTransportMapContainerView* view = (CPublicTransportMapContainerView*)iAvkonViewAppUi->View( TUid::Uid( EPublicTransportMapContainerViewId ) );
	CSingaporeBusDocument* doc = (CSingaporeBusDocument*)CEikonEnv::Static()->EikAppUi()->Document();
	TCoordinate prevOrig = view->iOrig;
	view->iOrig = aCoord; // to prepare YScale(view->iOrig)
	view->iOrig = TCoordinate(
			aCoord.Latitude() + kTilesResolutions[view->iZoomLevel]*YScale(view->iOrig) * Rect().Height() / 2,
			aCoord.Longitude() - kTilesResolutions[view->iZoomLevel] * Rect().Width() / 2);
	if(view->iZoomLevel >= kZoomLevelDisplayStations)
		{
		RefreshVisibleStationsL();
		TCoordinate shift (
				view->iOrig.Latitude() - prevOrig.Latitude(),
				view->iOrig.Longitude() - prevOrig.Longitude()
				);
		if(view->iSelectedStation && iVisibleStations.Find(view->iSelectedStation) == KErrNotFound)
			view->iSelectedStation = FindNextVisibleStationL(view->iSelectedStation, shift);
		if(!view->iSelectedStation && iVisibleStations.Count() != 0)
			view->iSelectedStation = iVisibleStations[0];
		view->UpdateTitle();
		}
	doc->iMapTileServer->DownloadVisibleTilesL(view->iOrig, view->iZoomLevel, Rect().Size());
	}


#if !defined(__SERIES60_3X__) || defined(__S60_50__)
void CPublicTransportMapContainer::HandleTitlePaneEventL( TInt aEventID )
	{
    if (aEventID == EAknTitlePaneTapped)
    {
	CSingaporeBusDocument* doc = (CSingaporeBusDocument*)CEikonEnv::Static()->EikAppUi()->Document();
	if(doc->iPositioningStatus == CSingaporeBusDocument::PS_FOUND)
		CenterMapOn(doc->iPosition);
	DrawToBackBuffer();
	DrawDeferred();
    }
	}

void CPublicTransportMapContainer::HandleLongTapEventL(const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	iLongTapUnderWay = ETrue;
	CPublicTransportMapContainerView* view = (CPublicTransportMapContainerView*)iAvkonViewAppUi->View( TUid::Uid( EPublicTransportMapContainerViewId ) );
	view->MenuBar()->SetContextMenuTitleResourceId(R_PUBLIC_TRANSPORT_MAP_CONTAINER_MARK_CONTEXT_MENU);
	view->MenuBar()->TryDisplayContextMenuBarL();
	}
TBool CPublicTransportMapContainer::LongTapPointerEventL(const TPointerEvent& aPointerEvent)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	iLongTapDetector->PointerEventL(aPointerEvent);
	if(iLongTapUnderWay)
		{
		if(aPointerEvent.iType == TPointerEvent::EButton1Up)
			iLongTapUnderWay = EFalse;
		return ETrue;
		}
	else
		return EFalse; // let the listbox handle the event too
	}
#endif

void CPublicTransportMapContainer::OfferToolbarEventL(TInt aCommand)
{
TFunTrace funTrace(__PRETTY_FUNCTION__);
CPublicTransportMapContainerView* view = (CPublicTransportMapContainerView*)iAvkonViewAppUi->View( TUid::Uid( EPublicTransportMapContainerViewId ) );
    view->HandleCommandL(aCommand); // In this example we are simply calling HandleCommandL by passing received command
}	



